{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bd089da3-c199-4d84-aa60-e0085ca85509",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-10-08T12:43:31.713470Z",
     "iopub.status.busy": "2025-10-08T12:43:31.712081Z",
     "iopub.status.idle": "2025-10-08T12:43:34.128868Z",
     "shell.execute_reply": "2025-10-08T12:43:34.128396Z",
     "shell.execute_reply.started": "2025-10-08T12:43:31.713440Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading Model from https://www.modelscope.cn to directory: /mnt/workspace/.cache/modelscope/models/google-bert/bert-base-chinese\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Some weights of BertForSequenceClassification were not initialized from the model checkpoint at /mnt/workspace/.cache/modelscope/models/google-bert/bert-base-chinese and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
      "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading Model from https://www.modelscope.cn to directory: /mnt/workspace/.cache/modelscope/models/google-bert/bert-base-chinese\n",
      "ModelScope输入形状:\n",
      "input_ids: torch.Size([32, 10])\n",
      "attention_mask: torch.Size([32, 10])\n",
      "模型输出logits形状: torch.Size([32, 2])\n"
     ]
    }
   ],
   "source": [
    "from modelscope import AutoModelForSequenceClassification, AutoTokenizer\n",
    "from modelscope.trainers import build_trainer\n",
    "from modelscope.metainfo import Trainers\n",
    "from modelscope.msdatasets import MsDataset\n",
    "import torch\n",
    "import datasets\n",
    "from torch.utils.data import DataLoader\n",
    "from transformers import (\n",
    "    DataCollatorWithPadding,\n",
    "    TrainingArguments,\n",
    "    Trainer,\n",
    ")\n",
    "from sklearn.metrics import (\n",
    "    accuracy_score,\n",
    "    precision_recall_fscore_support,\n",
    ")\n",
    "import datasets\n",
    "\n",
    "\n",
    "def check_modelscope_bert():\n",
    "    # 初始化ModelScope的模型和tokenizer\n",
    "    model = AutoModelForSequenceClassification.from_pretrained(\n",
    "        'google-bert/bert-base-chinese', \n",
    "        num_labels=2\n",
    "    )\n",
    "    tokenizer = AutoTokenizer.from_pretrained('google-bert/bert-base-chinese')\n",
    "    \n",
    "    # 模拟输入数据\n",
    "    texts = [\"这是一个测试句子\"] * 32\n",
    "    inputs = tokenizer(\n",
    "        texts, \n",
    "        padding=True, \n",
    "        truncation=True, \n",
    "        return_tensors=\"pt\", \n",
    "        max_length=128\n",
    "    )\n",
    "    \n",
    "    print(\"ModelScope输入形状:\")\n",
    "    print(f\"input_ids: {inputs['input_ids'].shape}\")\n",
    "    print(f\"attention_mask: {inputs['attention_mask'].shape}\")\n",
    "    \n",
    "    # 前向传播\n",
    "    outputs = model(**inputs)\n",
    "    print(f\"模型输出logits形状: {outputs.logits.shape}\")\n",
    "    \n",
    "    return model, tokenizer\n",
    "model, tokenizer = check_modelscope_bert()\n",
    "\n",
    "def tokenize_function(examples):\n",
    "    return tokenizer(examples['SentimentText'], padding=\"max_length\", truncation=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "39ad68c3-b3a1-4bd9-9dde-cdfc2adea892",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-10-08T12:43:38.308499Z",
     "iopub.status.busy": "2025-10-08T12:43:38.308191Z",
     "iopub.status.idle": "2025-10-08T12:43:52.442532Z",
     "shell.execute_reply": "2025-10-08T12:43:52.442058Z",
     "shell.execute_reply.started": "2025-10-08T12:43:38.308479Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "848d2253c666498cb77662d83efa009d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Generating train split: 0 examples [00:00, ? examples/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "efe67ced42b1452a9563722b4522f9c4",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Generating test split: 0 examples [00:00, ? examples/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "3cc368a9d0fe4c4d894ef692637dd913",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Map:   0%|          | 0/45013 [00:00<?, ? examples/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9b3b0839f7014b4a83d8375cc128117f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Map:   0%|          | 0/4988 [00:00<?, ? examples/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "data_path = {'train': 'data/train.csv', 'test': 'data/dev.csv'}\n",
    "raw_datasets = datasets.load_dataset('csv', data_files=data_path, delimiter=',')\n",
    "tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)\n",
    "data_collator = DataCollatorWithPadding(tokenizer=tokenizer)\n",
    "train_dataset = tokenized_datasets['train'].shuffle(seed=114514)\n",
    "eval_dataset = tokenized_datasets['test'].shuffle(seed=114514)\n",
    "\n",
    "\n",
    "def compute_metrics(pred):\n",
    "    labels = pred.label_ids\n",
    "    preds = pred.predictions.argmax(-1)\n",
    "    precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='weighted')\n",
    "    acc = accuracy_score(labels, preds)\n",
    "    return {\n",
    "        'accuracy': acc,\n",
    "        'f1': f1,\n",
    "        'precision': precision,\n",
    "        'recall': recall,\n",
    "    }\n",
    "\n",
    "training_args = TrainingArguments(\n",
    "    output_dir='./review_trainer',\n",
    "    eval_strategy='epoch',\n",
    "    per_device_train_batch_size=32,\n",
    "    per_device_eval_batch_size=32,\n",
    "    learning_rate=5e-5,\n",
    "    num_train_epochs=3,\n",
    "    warmup_ratio=0.2,\n",
    "    logging_dir='./review_train_logs',\n",
    "    logging_strategy='epoch',\n",
    "    save_strategy='epoch',\n",
    "    report_to='tensorboard',\n",
    ")\n",
    "trainer = Trainer(\n",
    "    model=model,\n",
    "    args=training_args,\n",
    "    train_dataset=tokenized_datasets['train'],\n",
    "    eval_dataset=tokenized_datasets['test'],\n",
    "    data_collator=data_collator,\n",
    "    processing_class=tokenizer,\n",
    "    compute_metrics=compute_metrics,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "905e601b-ec98-4237-a5c5-a01cfb64990b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-10-08T12:44:20.842769Z",
     "iopub.status.busy": "2025-10-08T12:44:20.842377Z",
     "iopub.status.idle": "2025-10-08T13:54:52.618467Z",
     "shell.execute_reply": "2025-10-08T13:54:52.618033Z",
     "shell.execute_reply.started": "2025-10-08T12:44:20.842741Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      \n",
       "      <progress value='4221' max='4221' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      [4221/4221 1:10:28, Epoch 3/3]\n",
       "    </div>\n",
       "    <table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       " <tr style=\"text-align: left;\">\n",
       "      <th>Epoch</th>\n",
       "      <th>Training Loss</th>\n",
       "      <th>Validation Loss</th>\n",
       "      <th>Accuracy</th>\n",
       "      <th>F1</th>\n",
       "      <th>Precision</th>\n",
       "      <th>Recall</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>0.303500</td>\n",
       "      <td>0.243817</td>\n",
       "      <td>0.903368</td>\n",
       "      <td>0.903334</td>\n",
       "      <td>0.903513</td>\n",
       "      <td>0.903368</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>0.234100</td>\n",
       "      <td>0.274492</td>\n",
       "      <td>0.908982</td>\n",
       "      <td>0.908945</td>\n",
       "      <td>0.909172</td>\n",
       "      <td>0.908982</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>0.176000</td>\n",
       "      <td>0.261374</td>\n",
       "      <td>0.909182</td>\n",
       "      <td>0.909192</td>\n",
       "      <td>0.909350</td>\n",
       "      <td>0.909182</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table><p>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "trainer.train()\n",
    "trainer.save_model('./review_model')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
